package edu.gzhu.guli.core.security.jwt;

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.security.Keys;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.util.StringUtils;

import javax.crypto.SecretKey;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.stream.Collectors;

public class JwtTokenUtils {
  private static byte[] apiKeySecretBytes = Base64.getEncoder()
      .encode(SecurityConstants.JWT_SECRET_KEY.getBytes(StandardCharsets.UTF_8));
  private static SecretKey secretKey = Keys.hmacShaKeyFor(apiKeySecretBytes);

  public static String createToken(String username, List<String> roles, boolean isRememberMe) {
    long expiration = isRememberMe ? SecurityConstants.EXPIRATION_REMEMBER : SecurityConstants.EXPIRATION;
    String tokenPrefix = Jwts.builder()
        .setHeaderParam("typ", SecurityConstants.TOKEN_TYPE)
        .signWith(secretKey, SignatureAlgorithm.HS256)
        .claim(SecurityConstants.ROLE_CLAIMS, String.join(",", roles))
        .setIssuer("AJinGo")
        .setIssuedAt(new Date())
        .setSubject(username)
        .setExpiration(new Date(System.currentTimeMillis() + expiration))
        .compact();
    return SecurityConstants.TOKEN_PREFIX + " " + tokenPrefix;
  }

  public static boolean isTokenExpired(String token) {
    Date expiredDate = getTokenBody(token).getExpiration();
    return expiredDate.before(new Date());
  }

  public static String getUsernameByToken(String token) {
    return getTokenBody(token).getSubject();
  }

  public static List<SimpleGrantedAuthority> getUserRolesByToken(String token) {
    String role = (String) getTokenBody(token).get(SecurityConstants.ROLE_CLAIMS);
    if (!StringUtils.hasText(role)) {
      return Collections.emptyList();
    }
    return Arrays.stream(role.split(","))
        .map(SimpleGrantedAuthority::new)
        .collect(Collectors.toList());
  }

  private static Claims getTokenBody(String token) {
    return Jwts.parserBuilder()
        .setSigningKey(secretKey)
        .build()
        .parseClaimsJws(token)
        .getBody();
  }
}
